package com.ews.onlineexchange.controller.assess;

import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.enterprise.context.ConversationScoped;
import javax.enterprise.event.Event;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

import com.ews.onlineexchange.controller.ServiceSupplierHome;
import com.ews.onlineexchange.controller.ServiceSupplierManageList;
import com.ews.onlineexchange.controller.activitii.BpmHome;
import com.ews.onlineexchange.enumType.RecordStatus;
import com.ews.onlineexchange.model.Attachment;
import com.ews.onlineexchange.model.Image;
import com.ews.onlineexchange.model.ServiceSupplier;
import com.ews.onlineexchange.model.User;
import com.ews.onlineexchange.model.assess.AssessRecord;
import com.ews.onlineexchange.model.assess.Dict;
import com.ews.onlineexchange.service.EntityHome;
import com.ews.onlineexchange.service.UserService;
import com.ews.onlineexchange.service.assess.AssessRecordService;
import com.ews.onlineexchange.service.qualifier.AssessRecodOperationEvent;
import com.ews.onlineexchange.util.AttachmentUtils;
import com.ews.onlineexchange.util.PeriodUtils;

@Named
@ConversationScoped
public class AssessRecordHome extends EntityHome<AssessRecord, String> {

	/**
	 * 
	 */
	private static final long	serialVersionUID	= 1L;

	@Inject
	AssessRecordService			assessRecordService;

	@Inject
	UserService					userService;

	@Inject
	ServiceSupplierManageList	serviceSupplierManageList;

	@Inject
	DictHome					dictHome;

	@Inject
	ServiceSupplierHome			serviceSupplierHome;

	@Inject
	ExistAssessRecordHome		existAssessRecordHome;

	@Inject
	@AssessRecodOperationEvent
	Event<Object[]>				assessRecodOperationEvent;

	@Inject
	BpmHome						bpmHome;

	@Inject
	RuntimeService				runtimeService;

	@Inject
	TaskService					taskService;
	
	@Inject
	AttachmentUtils 			attachmentUtils;
	
	private String				approvalDesc;
	
	@Override
	public AssessRecord createInstance() {
		
		AssessRecord instance = super.createInstance();
		
		if ( dictHome.isManaged() ) {
			instance.setDict( dictHome.getInstance() );
		}
		
		if ( serviceSupplierHome.isManaged() ) {
			instance.setServiceSupplier( serviceSupplierHome.getInstance() );
		}
		
		return instance;
		
	}

	@Override
	public AssessRecord loadInstance() {		
		AssessRecord instance = super.loadInstance();
		if(instance.getScore() == null)instance.setScore(instance.getDict().getMinScore());
		ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey( instance.getId() ).singleResult();
		if ( process != null ) {
			bpmHome.setProcessId( process.getId() );
		}
		return instance;
	}

	@Override
	public String saveAndFlush() {
		
		getInstance().setAssessDate( new Date() );
		
		if ( !isManaged() ) { 
			getInstance().setPeriodYear( PeriodUtils.getPeriodYear( getInstance().getDict().getPeriodType() ) );
			getInstance().setPeriodSeqNo( PeriodUtils.getPeriodSn( getInstance().getDict().getPeriodType() ) );
			
			if ( getInstance().getScore() == null && getInstance().getDict().getMaxScore().equals( getInstance().getDict().getMinScore() ) ) {
				getInstance().setScore( getInstance().getDict().getMaxScore() );
			}
		}
		
		String result = super.saveAndFlush();
		
//		existAssessRecordHome.setSupplier( getInstance().getServiceSupplier() );
//		existAssessRecordHome.setDict( getInstance().getDict() );
		
		if ( existAssessRecordHome.isManaged() ) {
			existAssessRecordHome.getInstance().setOverride( true );
			existAssessRecordHome.saveAndFlush();
			
			if ( existAssessRecordHome.getInstance().getRecordStatus().equals( RecordStatus.Keeped ) ) {				
				getInstance().getServiceSupplier().setCreditScore( getInstance().getServiceSupplier().getCreditScore().subtract( existAssessRecordHome.getInstance().getScore() ) );
				getEntityManagerDao().updateObject( getInstance().getServiceSupplier() );
			}
		}
		
		if ( result.equals( RESULT_SAVED ) ) {
			return "AssessRecordList.xhtml?faces-redirect=true&amp;includeViewParams=true";
		} else
			return null;
		
	}
	
	public String backendSaveAndFlush() {
		String result = this.saveAndFlush();
		if ( result != null ) {
			startBackendAssessRecordProcess();
			
			return "AssessRecordList.xhtml?faces-redirect=true";
		}
		
		return null;
	}
	
	private void startBackendAssessRecordProcess() {
		Task task = null;
		if ( StringUtils.isBlank( bpmHome.getTaskId() ) ) {
			HashMap<String, Object> variables = new HashMap<String, Object>();
			variables.put( "initiator", userService.getLoginedUser().getUsername() );
			variables.put( "dictId", getInstance().getDict().getId() );
			variables.put( "assessRecordId", getInstance().getId() );
			variables.put( "periodTypeName", getInstance().getDict().getPeriodType().name() );
			variables.put( "supplierName", getInstance().getServiceSupplier().getCnname());
			variables.put( "supplierRegion", getInstance().getServiceSupplier().getRegion());
			if ( userService.hasRole( "secretary" ) ) {
				variables.put( "initiatorRole", "secretary" );
			} else if ( userService.hasRole( "director" ) ) {
				variables.put( "initiatorRole", "director" );
			} else {
				variables.put( "initiatorRole", "worker" );
			}
						
			Map beanMap = new BeanMap( getInstance() );			
			variables.putAll( beanMap );
			
			ProcessInstance process = runtimeService.startProcessInstanceByKey( "backendAssessRecordAudit", getInstance().getId(), variables );			
			
			List<Task> list = taskService.createTaskQuery().processInstanceId( process.getId() ).list();
			task = list.get( 0 );			
		} else {
			task = taskService.createTaskQuery().taskId( bpmHome.getTaskId() ).singleResult();
		}
		
		taskService.claim( task.getId(), userService.getLoginedUser().getUsername() );
		taskService.complete( task.getId() );
	}

	public String supplierSaveAndFlush() {
		String result = this.saveAndFlush();
		if ( result != null ) {
			startSupplierAssessRecordProcess();
			
			return "AssessRecordForSupplierList.xhtml?periodType=" + dictHome.getInstance().getPeriodType().name() + "&amp;faces-redirect=true";
		}
		
		return null;
	}
	
	@SuppressWarnings( "unchecked" )
	private void startSupplierAssessRecordProcess() {
		Task task = null;
		if ( StringUtils.isBlank( bpmHome.getTaskId() ) ) {
			HashMap<String, Object> variables = new HashMap<String, Object>();
			variables.put( "initiator", userService.getLoginedUser().getUsername() );
			variables.put( "dictId", getInstance().getDict().getId() );
			variables.put( "assessRecordId", getInstance().getId() );
			variables.put( "periodTypeName", getInstance().getDict().getPeriodType().name() );
			variables.put( "supplierName", getInstance().getServiceSupplier().getCnname());			
			Map beanMap = new BeanMap( getInstance() );			
			variables.putAll( beanMap );
			
			ProcessInstance process = runtimeService.startProcessInstanceByKey( "supplierAssessRecordAudit", getInstance().getId(), variables );			
			
			List<Task> list = taskService.createTaskQuery().processInstanceId( process.getId() ).list();
			task = list.get( 0 );			
		} else {
			task = taskService.createTaskQuery().taskId( bpmHome.getTaskId() ).singleResult();
		}
		
		taskService.claim( task.getId(), userService.getLoginedUser().getUsername() );
		taskService.complete( task.getId() );
	}
	
	public String auditSuccess() {		
		if ( bpmHome.getTask().getTaskDefinitionKey().equals( "workerApprove" ) ) {
			this.saveAndFlush();
		}
		
		String taskId = bpmHome.getTaskId(); 
		taskService.claim( taskId, userService.getLoginedUser().getUsername() );
		taskService.setVariable( taskId, "approvalResult", true );
		taskService.setVariable( taskId, "approvalDesc", getApprovalDesc() );
		taskService.setVariable( taskId,"supplierName", getInstance().getServiceSupplier().getCnname());	
		taskService.setVariableLocal( taskId, "approvalResult", true );
		taskService.setVariableLocal( taskId, "approvalDesc", getApprovalDesc() );
		
		taskService.complete( taskId );		
		
		if (!conversation.isTransient())
			conversation.end();
		
		return "pendingReviewTaskList.xhtml?faces-redirect=true";
	}
	
	public String auditFail() {
		String taskId = bpmHome.getTaskId(); 
		taskService.claim( taskId, userService.getLoginedUser().getUsername() );
		taskService.setVariable( taskId, "approvalResult", false );
		taskService.setVariable( taskId, "to", "supplier" );
		taskService.setVariable( taskId, "approvalDesc", getApprovalDesc() );
		taskService.setVariable( taskId,"supplierName", getInstance().getServiceSupplier().getCnname());	
		taskService.setVariableLocal( taskId, "approvalResult", false );
		taskService.setVariableLocal( taskId, "approvalDesc", getApprovalDesc() );
		taskService.complete( taskId );		
		
		getInstance().setScore( null );
		if ( getInstance().getScore() == null && getInstance().getDict().getMaxScore().equals( getInstance().getDict().getMinScore() ) ) {
			getInstance().setScore( getInstance().getDict().getMaxScore() );
		}
		this.saveAndFlush();
		
		return "pendingReviewTaskList.xhtml?faces-redirect=true";
	}
	
	public String auditScoreFail() {
		String taskId = bpmHome.getTaskId(); 
		taskService.claim( taskId, userService.getLoginedUser().getUsername() );
		taskService.setVariable( taskId, "approvalResult", false );
		taskService.setVariable( taskId, "to", "worker" );
		taskService.setVariable( taskId, "approvalDesc", getApprovalDesc() );
		taskService.setVariableLocal( taskId, "approvalResult", false );
		taskService.setVariableLocal( taskId, "approvalDesc", getApprovalDesc() );
		taskService.complete( taskId );
		
		getInstance().setScore( null );
		this.saveAndFlush();
		
		return "pendingReviewTaskList.xhtml?faces-redirect=true";
	}
	
	public String delete() {
		User user = userService.getLoginedUser();
		getInstance().setRecordStatus( RecordStatus.Deleted );
		String result = super.saveAndFlush();
		if ( result.equals( RESULT_SAVED ) ) {
			assessRecodOperationEvent.fire( new Object[] { user, getInstance() } );
			return "AssessRecordList.xhtml?faces-redirect=true&amp;includeViewParams=true";
		} else
			return null;
	}
	
	public void dictChange() {
		getInstance().setScore(null);
		Dict dict = getInstance().getDict();
		if(dict.getMinScore().equals(dict.getMaxScore())) getInstance().setScore(dict.getMaxScore());
	}
	
	public void uploadImage(FileUploadEvent event) {
		if (event.getFile() == null)
			return ;
		Image image = attachmentUtils.getImageFromUpload(event.getFile());
		getInstance().getImages().add(image);
		FacesMessage message = new FacesMessage(image.getFilename() + " 上传成功。");
        FacesContext.getCurrentInstance().addMessage(null, message);
	}
	
	public StreamedContent getPhotoStreamedContent(Image image) {
		if (image == null)
			return null;
		return new DefaultStreamedContent(new ByteArrayInputStream(image.getFiledata()));
	}
	
	public void removeImage(int index) {
		getInstance().getImages().remove(index);
	}
	
	public void removeAttachment(int index) {
		getInstance().getAttachments().remove(index);
	}
	
	public void uploadAttachments(FileUploadEvent event) {
		if (event.getFile() == null)
			return ;
		
		Attachment attr  = attachmentUtils.getAttachmentFromUpload(event.getFile());
		
		getInstance().getAttachments().add(attr);
		FacesMessage message = new FacesMessage(event.getFile().getFileName() + " 上传成功。");
        FacesContext.getCurrentInstance().addMessage(null, message);
	}
	
	public List<ServiceSupplier> filterSupplier(String query) {
		serviceSupplierManageList.refresh();
		serviceSupplierManageList.setMaxResults(null);
		serviceSupplierManageList.setCnname(query);
        List<ServiceSupplier> suppliers = serviceSupplierManageList.getResultList();
         
        return suppliers;
	}

	@Length( max = 255 )
	public String getApprovalDesc() {
		return approvalDesc;
	}

	public void setApprovalDesc( String approvalDesc ) {
		this.approvalDesc = approvalDesc;
	}	
}

	
